﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace KKSGameLibrary.Logic
{
    public class CardInMap
    {
        const uint Left_DirectionMask = 0xFF000000;
        const uint Top_DirectionMask = 0x00FF0000;
        const uint Right_DirectionMask = 0x0000FF00;
        const uint Bottom_DirectionMask = 0x000000FF;

        //public CardInMap

        public Card Card { set; get; }
        public RotationDegree Rotation { set; get; }
        public int Row { set; get; }
        public int Column { set; get; }

        //internal CardInMap() { }

        internal int GetCastleData()
        {
            //if ((cardim.Card.CardType & CardType.Castle) == 0)
            //    throw new Exception("not castle card");

            int data = 0;
            switch (this.Rotation)
            {
                case RotationDegree.D0:
                    data = this.Card.CastleData;
                    break;
                case RotationDegree.D90:
                    data = this.Card.CastleData >> 8;
                    data |= (this.Card.CastleData & 0xFF) << 24;
                    break;
                case RotationDegree.D180:
                    data = this.Card.CastleData >> 16;
                    data |= (this.Card.CastleData & 0xFFFF) << 16;
                    break;
                case RotationDegree.D270:
                    data = this.Card.CastleData >> 24;
                    data |= (this.Card.CastleData & 0xFFFFFF) << 8;
                    break;
                default:
                    break;
            }
            return data;
        }

        internal int GetRoadData()
        {
            //if ((cardim.Card.CardType & CardType.Road) == 0)
            //    throw new Exception("not road card");

            int data = 0;
            switch (this.Rotation)
            {
                case RotationDegree.D0:
                    data = this.Card.RoadData;
                    break;
                case RotationDegree.D90:
                    data = this.Card.RoadData >> 8;
                    data |= (this.Card.RoadData & 0xFF) << 24;
                    break;
                case RotationDegree.D180:
                    data = this.Card.RoadData >> 16;
                    data |= (this.Card.RoadData & 0xFFFF) << 16;
                    break;
                case RotationDegree.D270:
                    data = this.Card.RoadData >> 24;
                    data |= (this.Card.RoadData & 0xFFFFFF) << 8;
                    break;
                default:
                    break;
            }
            return data;
        }

        public OpenEdge GetEdge(OpenDirection dir)
        {
            int castledata = GetCastleData();
            if ((castledata & GetDirectionMask(dir)) > 0)
                return new OpenEdge
                {
                    Row = this.Row,
                    Column = this.Column,
                    EdgeCardType = CardType.Castle,
                    OpenDirection = dir
                };

            int roaddata = GetRoadData();
            if ((roaddata & GetDirectionMask(dir)) > 0)
                return new OpenEdge
                {
                    Row = this.Row,
                    Column = this.Column,
                    EdgeCardType = CardType.Road,
                    OpenDirection = dir
                };

            return new OpenEdge
            {
                OpenDirection = dir,
                EdgeCardType = CardType.Empty,
                Column = this.Column,
                Row = this.Row
            };
        }

        public List<OpenEdge> GetInnerConnectEdges(OpenDirection dir)
        {
            var retlist = new List<OpenEdge>();
            OpenEdge curedge = GetEdge(dir);

            if (curedge.EdgeCardType==CardType.Empty)
                return retlist;

            // get same type all edges.
            Dictionary<OpenDirection, int> castledatas = null;
            switch (curedge.EdgeCardType)
            {
                case CardType.Castle:
                    castledatas = SeparateInt(GetCastleData());
                    break;
                case CardType.Road:
                    castledatas = SeparateInt(GetRoadData());
                    break;
                case CardType.Church:
                    break;
                case CardType.River:
                    break;
                default:
                    break;
            }

            // filter same value edges
            var innerconnectdirs = castledatas
                .Where(p => p.Value == castledatas[dir])
                .Select(p => p.Key).ToList();

            // remvoe self
            // innerconnectdirs.Remove(dir);

            // add to edge list
            foreach (var mydir in innerconnectdirs)
                retlist.Add(GetEdge(mydir));

            return retlist;
        }

        Dictionary<OpenDirection,int> SeparateInt(int data)
        {
            var ret = new Dictionary<OpenDirection, int>();
            ret[OpenDirection.Left] = (int)(data & Left_DirectionMask)>>24;
            ret[OpenDirection.Top] = (int)(data & Top_DirectionMask)>>16;
            ret[OpenDirection.Right] = (int)(data & Right_DirectionMask)>>8;
            ret[OpenDirection.Bottom] = (int)(data & Bottom_DirectionMask);

            return ret;
        }

        uint GetDirectionMask(OpenDirection dir)
        {
            uint dirmask = 0;
            switch (dir)
            {
                case OpenDirection.Left:
                    dirmask = Left_DirectionMask;
                    break;
                case OpenDirection.Top:
                    dirmask = Top_DirectionMask;
                    break;
                case OpenDirection.Right:
                    dirmask = Right_DirectionMask;
                    break;
                case OpenDirection.Bottom:
                    dirmask = Bottom_DirectionMask;
                    break;
                default:
                    break;
            }
            return dirmask;
        }

        //public bool IsEqual(CardInMap cardim)
        //{
        //    return 
        //        this.Card.IsEqual(cardim.Card) &&
        //        this.Column==cardim.c
        //}
    }

    public enum RotationDegree
    {
        D0 = 0,
        D90,
        D180,
        D270
    }
}
